package com.situ.shoplook.dubbo.service.impl;

import com.situ.shoplook.common.model.Category;
import com.situ.shoplook.common.service.CategoryService;
import com.situ.shoplook.dubbo.dao.CategoryDao;
import com.situ.shoplook.dubbo.util.CannotDeleteNodeException;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@CacheConfig(cacheNames = "c.s.s.d.s.impl.CategoryServiceImpl")
@Service
@DubboService
public class CategoryServiceImpl implements CategoryService {
    private CategoryDao categoryDao;

    @Autowired
    public void setCategoryDao(CategoryDao categoryDao) {
        this.categoryDao = categoryDao;
    }

    @Cacheable(keyGenerator = "myKeyGenerator")
    @Override
    public List<Category> findAll() {
        return this.categoryDao.findAll();
    }

    @Cacheable(keyGenerator = "myKeyGenerator")
    @Override
    public Category findTree() {
        //获取当前类的动态代理实例
        CategoryService cs = (CategoryService) AopContext.currentProxy();
        //this不是动态代理实例，cs才是
        List<Category> categories = cs.findAll();
        return makeTree(categories);
    }

    @Cacheable(keyGenerator = "myKeyGenerator")
    @Override
    public Category findById(Integer id) {
        CategoryService cs = (CategoryService) AopContext.currentProxy();
        Category root = cs.findTree();

        if (root.getId().equals(id)) {
            return root;
        } else {
            return deepFindById(root.getChildren(), id);
        }
    }

    @CacheEvict(allEntries = true)
    @Override
    public boolean save(Category category) {
        return this.categoryDao.save(category) > 0;
    }

    @CacheEvict(allEntries = true)
    @Override
    public boolean update(Category category) {
        return this.categoryDao.update(category) > 0;
    }

    @Transactional
    @CacheEvict(allEntries = true)
    @Override
    public int deleteByIds(Integer[] ids) {
        int count = 0;
        for (Integer id : ids) {
            count += deleteById(id);
        }
        return count;
    }
//根据类别名查出
    @Override
    public Category findByName(String name) {
        return categoryDao.findByName(name);
    }

    @Override
    public Category findByParentId(Integer id) {
        return categoryDao.findByParentId(id);
    }

    @Override
    public List<Integer> findChildren(Integer id) {
        List<Integer> ids = new ArrayList<>();
        List<Integer> childIds = categoryDao.findChildren(id);
        while (!childIds.isEmpty()) {
            ids.addAll(childIds);
            List<Integer> tempIds = new ArrayList<>(childIds);
            childIds.clear();
            for (Integer tempId : tempIds) {
                List<Integer> subChildIds = categoryDao.findChildren(tempId);
                childIds.addAll(subChildIds);
            }
        }
        return ids;
    }



    //删除一个类别实体
    //@Transactional
    private int deleteById(Integer id) {
        CategoryService cs = (CategoryService) AopContext.currentProxy();
        //可以触发aop
        Category cat = cs.findById(id);
        if (cat != null) {
            //获取节点的所有子节点
            List<Category> children = cat.getChildren();
            if (children != null && !children.isEmpty()) {
                /*for (Category child : children) {
                    deleteById(child.getId());
                }*/
                throw new CannotDeleteNodeException("有子节点不能删除");
            }
        }
        return this.categoryDao.deleteByIds(new Integer[]{id});
    }

    /**
     * 生成类别树
     *
     * @param categories 所有类别实例
     * @return 根节点
     */
    private static Category makeTree(List<Category> categories) {
        Map<Integer, Category> cache = new HashMap<>();
        categories.forEach(t -> cache.put(t.getId(), t));

        List<Category> roots = new ArrayList<>();
        for (Category cat : categories) {
            if (cat.getParentId() == null) {
                roots.add(cat);
            } else {
                //到缓存中找出父类别
                Category parent = cache.get(cat.getParentId());
                if (parent.getChildren() == null) {
                    parent.setChildren(new ArrayList<>());
                }
                parent.getChildren().add(cat);
            }
        }

        if (roots.size() == 1) {
            return roots.getFirst();
        } else {
            //自定义一个根类
            Category root = new Category();
            root.setId(0);
            root.setName("root");
            root.setChildren(new ArrayList<>());

            for (Category r : roots) {
                root.getChildren().add(r);
                r.setParentId(root.getId());
            }
            return root;
        }
    }

    //在树上查询指定编号的节点
    private static Category deepFindById(List<Category> categories, Integer id) {
        if (categories == null || categories.isEmpty()) {
            return null;
        }
        for (Category cat : categories) {
            if (cat.getId().equals(id)) {
                return cat;
            }

            if (cat.getChildren() != null) {
                Category c = deepFindById(cat.getChildren(), id);
                if (c != null) {
                    return c;
                }
            }
        }
        return null;
    }
}
